package com.aipp.mall.h5.service;

import com.aipp.mall.common.exception.ServerException;
import com.aipp.mall.common.model.LoginMember;
import com.aipp.mall.common.model.WechatPhoneNumberInfo;
import com.aipp.mall.common.model.WechatSessionResult;
import com.aipp.mall.common.redis.RedisCache;
import com.aipp.mall.common.redis.TokenService;
import com.aipp.mall.common.utils.*;
import com.aipp.mall.h5.domain.entity.Member;
import com.aipp.mall.h5.domain.entity.MemberLogininfor;
import com.aipp.mall.h5.domain.entity.MemberWechat;
import com.aipp.mall.h5.domain.form.H5SmsLoginForm;
import com.aipp.mall.h5.domain.vo.H5LoginVO;
import com.aipp.mall.h5.domain.vo.MemberVO;
import com.aipp.mall.h5.domain.vo.WechatLoginDTO;
import com.aipp.mall.h5.mapper.MemberLogininforMapper;
import com.aipp.mall.h5.mapper.MemberMapper;
import com.aipp.mall.h5.mapper.MemberWechatMapper;
import com.aipp.mall.wechat.WechatAuthService;
import com.aipp.mall.wechat.response.WechatUserAuth;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.codec.binary.Base64;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.http.meta.HeaderName;
import org.dromara.hutool.http.useragent.UserAgent;
import org.dromara.hutool.http.useragent.UserAgentUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;

/**
 * @author cc
 */
@Service
@Slf4j
public class H5MemberService {

    @Resource
    private MemberMapper memberMapper;

    @Resource
    private RedisCache redisCache;

    @Resource
    private TokenService tokenService;

    @Value("${aes.key}")
    private String aesKey;

    @Resource
    private WechatAuthService wechatAuthService;

    @Resource
    private MemberWechatMapper memberWechatMapper;

    @Resource
    private MemberLogininforMapper memberLogininforMapper;


    public H5LoginVO wechatLogin(String data) {
        if (StrUtil.isEmpty(data)) {
            throw ServerException.spe("登录失败");
        }
        try {
            WechatLoginDTO dto = Json.toObj(Base64.decodeStr(data), WechatLoginDTO.class);
            if (dto == null) {
                throw ServerException.spe("登录失败");
            }
            WechatSessionResult wechatSession = wechatAuthService.getWechatSession(dto.getOpenIdCode());
            WechatPhoneNumberInfo phoneNoInfo = wechatAuthService.getPhoneNumber(dto.getPhoneCode());
            Member member = createOrUpdateMember(wechatSession.getOpenid(), phoneNoInfo.getPhoneNumber());
            return getLoginResponse(member.getId(), wechatSession.getOpenid());
        } catch (Exception e) {
            log.error("登录失败", e);
            throw ServerException.spe("登录失败");
        }
    }

    public H5LoginVO smsLogin(String data) {
        LocalDateTime optDate = LocalDateTime.now();
        if (StrUtil.isEmpty(data)) {
            throw new ServerException(Constants.LOGIN_INFO.WRONG);
        }
        H5SmsLoginForm request = Json.toObj(Base64.decodeStr(data), H5SmsLoginForm.class);
        // 校验验证码
        this.validateVerifyCode(request.getUuid(), request.getMobile(), request.getCode());
        // 查会员
        QueryWrapper<Member> qw = new QueryWrapper<>();
        qw.eq("phone_encrypted", AesCryptoUtils.encrypt(aesKey, request.getMobile()));
        Member member = memberMapper.selectOne(qw);
        if (member == null) {
            // 新会员，注册并登录
            member = new Member();
            member.setPhoneEncrypted(AesCryptoUtils.encrypt(aesKey, request.getMobile()));
            member.setPhoneHidden(PhoneUtils.hidePhone(request.getMobile()));
            member.setNickname("用户" + request.getMobile().substring(7, 11));
            member.setStatus(Constants.MEMBER_ACCOUNT_STATUS.NORMAL);
            member.setGender(0);
            member.setCreateTime(optDate);
            int rows = memberMapper.insert(member);
            if (rows < 1) {
                throw new ServerException("注册失败，请重试");
            }
            MemberWechat memberWechat = new MemberWechat();
            memberWechat.setMemberId(member.getId());
            if (request.getAuthInfo() != null) {
                memberWechat.setOpenid(request.getAuthInfo().getOpenid());
                memberWechat.setAccessToken(request.getAuthInfo().getAccess_token());
                memberWechat.setExpiresIn(request.getAuthInfo().getExpires_in());
                memberWechat.setRefreshToken(request.getAuthInfo().getRefresh_token());
            }
            if (StrUtil.isNotEmpty(request.getMpOpenId())) {
                memberWechat.setRoutineOpenid(request.getMpOpenId());
            }
            memberWechat.setCreateTime(optDate);
            memberWechat.setCreateBy(member.getId());
            rows = memberWechatMapper.insert(memberWechat);
            if (rows < 1) {
                throw new ServerException("注册失败，请重试");
            }
        } else {
            // 校验会员状态
            validateMemberStatus(member);
            // 判断小程序openid是否插入
            if (StrUtil.isNotEmpty(request.getMpOpenId()) || request.getAuthInfo() != null) {
                QueryWrapper<MemberWechat> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("member_id", member.getId());
                MemberWechat memberWechat = memberWechatMapper.selectOne(queryWrapper);
                boolean update = false;
                if (StrUtil.isNotEmpty(request.getMpOpenId()) && StrUtil.isEmpty(memberWechat.getRoutineOpenid())) {
                    memberWechat.setRoutineOpenid(request.getMpOpenId());
                    update = true;
                }
                if (request.getAuthInfo() != null && StrUtil.isEmpty(memberWechat.getOpenid())) {
                    memberWechat.setOpenid(request.getAuthInfo().getOpenid());
                    memberWechat.setAccessToken(request.getAuthInfo().getAccess_token());
                    memberWechat.setExpiresIn(request.getAuthInfo().getExpires_in());
                    memberWechat.setRefreshToken(request.getAuthInfo().getRefresh_token());
                    update = true;
                }
                if (update) {
                    memberWechatMapper.updateById(memberWechat);
                }
            }
        }
        return getLoginResponse(member.getId(),null);
    }

    /**
     * 校验会员状态
     *
     * @param member 会员信息
     */
    private void validateMemberStatus(Member member) {
        if (Constants.MEMBER_ACCOUNT_STATUS.FORBIDDEN.equals(member.getStatus())) {
            throw new ServerException(Constants.LOGIN_INFO.FORBIDDEN);
        }
    }

    /**
     * 校验验证码有效性
     *
     * @param uuid      唯一标识
     * @param phone     手机号
     * @param inputCode 输入的验证码
     */
    private void validateVerifyCode(String uuid, String phone, String inputCode) {
        String key = uuid + "_" + phone;
        String redisCode = redisCache.getCacheObject(key);
        if (redisCode == null) {
            throw new ServerException(Constants.VERIFY_CODE_INFO.EXPIRED);
        } else if (!redisCode.equals(inputCode)) {
            throw new ServerException(Constants.VERIFY_CODE_INFO.WRONG);
        }
        // 删除缓存
        redisCache.deleteObject(key);
    }

    /**
     * 封装登录响应
     *
     * @param memberId 登录会员id
     * @return 结果
     */
    public H5LoginVO getLoginResponse(Long memberId, String openId) {
        LoginMember loginMember = new LoginMember();
        loginMember.setMemberId(memberId);
        String token = tokenService.createMemberToken(loginMember);
        // record登录
        this.insert(memberId);
        H5LoginVO response = new H5LoginVO();
        response.setOpenId(openId);
        response.setToken(token);
        return response;
    }

    public MemberVO getMemberInfo() {
        Member member = LocalDataUtil.getVar();
        MemberVO memberVO = new MemberVO();
        BeanUtils.copyProperties(member, memberVO);
        memberVO.setPhone(AesCryptoUtils.decrypt(aesKey, member.getPhoneEncrypted()));
        QueryWrapper<MemberWechat> qw = new QueryWrapper<>();
        qw.eq("member_id", member.getId());
        MemberWechat memberWechat = memberWechatMapper.selectOne(qw);
        memberVO.setOpenId(memberWechat.getOpenid());
        return memberVO;
    }


    public void setWechatInfo(String data) {
        WechatUserAuth authInfo = Json.toObj(Base64.decodeStr(data), WechatUserAuth.class);
        Member member = LocalDataUtil.getVar();
        UpdateWrapper<MemberWechat> wrapper = new UpdateWrapper<>();
        wrapper.eq("member_id", member.getId());
        wrapper.set("openid", authInfo.getOpenid());
        wrapper.set("access_token", authInfo.getAccess_token());
        wrapper.set("expires_in", authInfo.getExpires_in());
        wrapper.set("refresh_token", authInfo.getRefresh_token());
        wrapper.set("update_time", LocalDateTime.now());
        wrapper.set("update_by", member.getId());
        memberWechatMapper.update(null, wrapper);
    }

    /**
     * 新增会员登录记录
     *
     * @param memberId 会员id
     */
    public void insert(Long memberId) {
        Member member = memberMapper.selectById(memberId);
        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        UserAgent userAgent = UserAgentUtil.parse(request.getHeader(HeaderName.USER_AGENT.getValue()));
        MemberLogininfor ml = new MemberLogininfor();
        ml.setMemberId(memberId);
        ml.setPhone(member.getPhoneHidden());
        ml.setOs(userAgent.getOs().getName());
        ml.setIpaddr(IpUtils.getIpAddr(request));
        ml.setBrowser(userAgent.getBrowser().getName());
        ml.setLoginLocation(IpUtils.getRealAddressByIp(ml.getIpaddr()));
        ml.setLoginTime(LocalDateTime.now());
        memberLogininforMapper.insert(ml);
    }


    private Member createOrUpdateMember(String openId, String phoneNumber) {
        // 查会员
        QueryWrapper<Member> qw = new QueryWrapper<>();
        qw.eq("phone_encrypted", phoneNumber);
        Member member = memberMapper.selectOne(qw);
        if (member == null) {
            // 新会员，注册并登录
            member = new Member();
            member.setPhoneEncrypted(AesCryptoUtils.encrypt(aesKey, phoneNumber));
            member.setPhoneHidden(PhoneUtils.hidePhone(phoneNumber));
            member.setNickname("用户" + phoneNumber.substring(7, 11));
            member.setStatus(Constants.MEMBER_ACCOUNT_STATUS.NORMAL);
            member.setGender(0);
            member.setCreateTime(LocalDateTime.now());
            int rows = memberMapper.insert(member);
            if (rows < 1) {
                throw new ServerException("注册失败，请重试");
            }
            MemberWechat memberWechat = new MemberWechat();
            memberWechat.setMemberId(member.getId());
            memberWechat.setRoutineOpenid(openId);
            memberWechat.setCreateTime(LocalDateTime.now());
            memberWechat.setCreateBy(member.getId());
            rows = memberWechatMapper.insert(memberWechat);
            if (rows < 1) {
                throw new ServerException("注册失败，请重试");
            }
        } else {
            QueryWrapper<MemberWechat> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("member_id", member.getId());
            MemberWechat memberWechat = memberWechatMapper.selectOne(queryWrapper);
            if (StrUtil.isEmpty(memberWechat.getRoutineOpenid())) {
                memberWechat.setRoutineOpenid(openId);
                memberWechatMapper.updateById(memberWechat);
            }
        }
        return member;
    }


    public Member selectById(Long memberId) {
        return memberMapper.selectById(memberId);
    }
}
